package com.bytedance.danmaku.render.engine.demo.danmu.widget.gradienttext

import android.graphics.Canvas
import android.graphics.Color
import android.graphics.LinearGradient
import android.graphics.Matrix
import android.graphics.Paint
import android.graphics.Shader
import android.text.TextUtils
import android.util.Log
import com.bytedance.danmaku.render.engine.control.DanmakuConfig
import com.bytedance.danmaku.render.engine.demo.utils.DRAW_TYPE_GRADIENT_TEXT
import com.bytedance.danmaku.render.engine.render.draw.DrawItem

/**
 * @Description:自定义渐变色文字
 * @Author yanxin
 * @Date:  2025/8/19
 */

open class GradientTextDrawItem: DrawItem<GradientTextData>()  {
    private val mTextPaint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.DITHER_FLAG)
    private val mStrokeTextPaint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.DITHER_FLAG)
    private val mUnderlinePaint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.DITHER_FLAG)
    // 渐变相关变量
    private var gradient: LinearGradient? = null
    private var lastText: String? = null
    private var lastTextWidth: Float = 0f
    private var lastGradientColors: IntArray? = null
    private val gradientMatrix = Matrix()
    override fun getDrawType(): Int {
        return DRAW_TYPE_GRADIENT_TEXT
    }

    override fun onBindData(data: GradientTextData) {
        mTextPaint.flags = Paint.ANTI_ALIAS_FLAG or Paint.DITHER_FLAG
        mUnderlinePaint.flags = Paint.ANTI_ALIAS_FLAG or Paint.DITHER_FLAG
    }

    override fun onMeasure(config: DanmakuConfig) {
        if (!TextUtils.isEmpty(data?.text)) {
            mTextPaint.textSize = data?.textSize ?: config.text.size
            width = mTextPaint.measureText(data?.text)
            val includeFontPadding = data?.includeFontPadding ?: config.text.includeFontPadding
            height = getFontHeight(includeFontPadding, mTextPaint)
        } else {
            width = 0F
            height = 0F
        }
    }

    override fun onDraw(canvas: Canvas, config: DanmakuConfig) {
        drawText(canvas,mStrokeTextPaint, mTextPaint, config)
        drawUnderline(canvas, mTextPaint, mUnderlinePaint, config)
    }

    override fun recycle() {
        super.recycle()
        mTextPaint.reset()
        mUnderlinePaint.reset()
    }

    /**
     * Canvas.drawText() is positioning the text by baseline
     */
    private fun drawText(canvas: Canvas,strokePaint: Paint, paint: Paint, config: DanmakuConfig) {
        data?.text?.let { text ->

            // draw stroke
            (data?.textStrokeWidth ?: config.text.strokeWidth).takeIf { it > 0 }?.let { width ->
                strokePaint.style = Paint.Style.STROKE
                strokePaint.color = data?.textStrokeColor ?: config.text.strokeColor
                strokePaint.typeface = data?.typeface ?: config.text.typeface
                strokePaint.textSize = data?.textSize ?: config.text.size
                strokePaint.strokeWidth = width
                val baseline = getBaseline(data?.includeFontPadding ?: true, y, strokePaint)
                canvas.drawText(text, x, baseline, strokePaint)
            }

            handleGradient(text)
            // draw drawText
            paint.style = Paint.Style.FILL
//            paint.color = data?.textColor ?: config.text.color
            paint.typeface = data?.typeface ?: config.text.typeface
            paint.textSize = data?.textSize ?: config.text.size
            paint.strokeWidth = 0f

            val includeFontPadding = data?.includeFontPadding ?: config.text.includeFontPadding
            val baseline = getBaseline(includeFontPadding, y, paint)
            canvas.drawText(text, x, baseline, paint)
        }
    }
    //todo: 优化避免每次文字移动都创建LinearGradient，每个文字创建一次其余都是根据坐标去移动
    private fun handleGradient(text: String) {
        val colors = intArrayOf(
            Color.parseColor("#FBAC45"),     // 起始颜色
            Color.parseColor("#FAF580"),     // 起始颜色
        )
        val textWidth = mTextPaint.measureText(text)

        // 只在以下情况重新创建渐变：
        // 1. 渐变不存在
        // 2. 文字内容变化
        // 3. 文字宽度变化
        // 4. 渐变色变化
        if (gradient == null ||
            !text.contentEquals(lastText)  ||
            !colors.contentEquals(lastGradientColors)) {
            Log.e("创建后TextDrawItem===","${gradient==null}=======${!text.contentEquals(lastText)} ================${colors.contentEquals(lastGradientColors)}")
            gradient = LinearGradient(
                0f, 0f, textWidth, 0f, // 渐变区域匹配文字宽度
                colors,
                null,
                Shader.TileMode.CLAMP
            ).apply {
                // 保存当前状态
                lastText = text
                lastTextWidth = textWidth
                lastGradientColors = colors.copyOf()
            }
            Log.e("创建后TextDrawItem", "handleGradient:${text}=====${lastText} ")
        }
        // 更新渐变位置（每次绘制都执行）
        gradientMatrix.reset()
        gradientMatrix.postTranslate(x, 0f) // 根据当前x位置偏移
        gradient?.setLocalMatrix(gradientMatrix)
        mTextPaint.shader = gradient
    }
    private fun drawUnderline(canvas: Canvas, textPaint: Paint, underlinePaint: Paint, config: DanmakuConfig) {
        takeIf { data?.hasUnderline == true }?.let {
            val includeFontPadding = data?.includeFontPadding ?: config.text.includeFontPadding
            val underlineY = y + getFontHeight(includeFontPadding, textPaint) + config.underline.marginTop
            // draw underline stroke
            takeIf {config.underline.strokeWidth > 0 }?.let {
                underlinePaint.style = Paint.Style.STROKE
                underlinePaint.color = config.underline.strokeColor
                underlinePaint.strokeWidth = config.underline.strokeWidth
                canvas.drawRect(x, underlineY, x + width, underlineY + config.underline.width, underlinePaint)
            }
            // draw underline
            underlinePaint.style = Paint.Style.FILL
            underlinePaint.color = data?.textColor ?: config.underline.color
            underlinePaint.strokeWidth = 0f
            canvas.drawRect(x, underlineY, x + width, underlineY + config.underline.width, underlinePaint)
        }
    }

    private fun getFontHeight(includeFontPadding: Boolean, paint: Paint): Float {
        return if (includeFontPadding)
            paint.fontMetrics.bottom - paint.fontMetrics.top
        else
            paint.fontMetrics.bottom - paint.fontMetrics.ascent
    }

    private fun getBaseline(includeFontPadding: Boolean, top: Float, paint: Paint): Float {
        return if (includeFontPadding) top - paint.fontMetrics.top else top - paint.fontMetrics.ascent
    }
}